/**
 * 
 */
package commons.base.http.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

/**
 * @author yuan<cihang.yuan@happyelements.com>
 * @since 1.7
 */
public class BasicHttpClient extends AbstractHttpClient{
	
	public BasicHttpClient(){
		this(null, 0);
	}
	
	public BasicHttpClient(String localHost, int localPort){
		super(new BasicHttpClientFactory(localHost, localPort));
	}
	
	public CloseableHttpResponse execute(HttpUriRequest request) throws ClientProtocolException, IOException{
		return super.httpClient.execute(request);
	}
	
	public static class BasicHttpClientFactory extends HttpClientFactory{
		private int localPort = 0;
		private String localHost;
		
		public BasicHttpClientFactory(String localHost, int localPort){
			super();
			this.localHost = localHost;
			this.localPort = localPort;
		}
		
		@Override
		protected HttpClientConnectionManager createHttpClientConnectionManager() {
			return new BasicHttpClientConnectionManager(getDefaultRegistry());
		}
		
		@Override
		protected ConnectionSocketFactory createSocketFactory(){
			return new PlainConnectionSocketFactory(){
	            @Override
	            public Socket connectSocket(
	                    final int connectTimeout,
	                    final Socket socket,
	                    final HttpHost host,
	                    final InetSocketAddress remoteAddress,
	                    final InetSocketAddress localAddress,
	                    final HttpContext context) throws IOException {
	                final Socket sock = socket != null ? socket : createSocket(context);
	                if (localHost != null) {
	                	sock.bind(new InetSocketAddress(localHost, localPort));
	                }
	                
	                try {
	                    sock.connect(remoteAddress, connectTimeout);
	                } catch (final IOException ex) {
	                    try {
	                        sock.close();
	                    } catch (final IOException ignore) {
	                    }
	                    throw ex;
	                }
	                return sock;
	            }
	        };
		}
	}
	
}
